package com.yzion.baselib.http.progress

import com.yzion.baselib.http.progress.ProgressHelper.Companion.dispatchErrorEvent
import com.yzion.baselib.http.progress.ProgressHelper.Companion.dispatchProgressEvent
import okhttp3.MediaType
import okhttp3.RequestBody
import okio.*
import java.io.IOException
import java.lang.ref.WeakReference

/**
 * 带进度回调的RequestBody
 */
class ProgressRequestBody(
    private val delegate: RequestBody,
    private val listeners: Set<WeakReference<ProgressListener>>
) : RequestBody() {

    private var bufferedSink: BufferedSink? = null

    override fun contentType(): MediaType? {
        return delegate.contentType()
    }

    override fun contentLength(): Long {
        try {
            return delegate.contentLength()
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return -1
    }

    @Throws(IOException::class)
    override fun writeTo(sink: BufferedSink) {
        if (bufferedSink == null) {
            bufferedSink = ProgressSink(sink).buffer()
        }
        try {
            delegate.writeTo(bufferedSink!!)
            bufferedSink!!.flush()
        } catch (e: IOException) {
            e.printStackTrace()
            dispatchErrorEvent(listeners, e)
            throw e
        }
    }

    internal inner class ProgressSink(delegate: Sink?) : ForwardingSink(
        delegate!!
    ) {
        private var soFarBytes: Long = 0
        private var totalBytes: Long = -1
        override fun write(source: Buffer, byteCount: Long) {
            try {
                super.write(source, byteCount)
            } catch (e: Exception) {
                dispatchErrorEvent(listeners, e)
            }
            if (totalBytes < 0) {
                totalBytes = contentLength()
            }
            soFarBytes += byteCount
            dispatchProgressEvent(listeners, soFarBytes, totalBytes)
        }
    }
}